/*
 *	CHANGE LOG
 * 
 * 01.02.02
 *
 *		12/23/2008 - DW - Updated the provider to add Authorization code in some of the procedures.  Did not
 *							add to all the procedures since the TabModuleID isn't available in some procedures
 *							and the TabModuleID is the moduleLevelId that's tracked for the module.
 *
 * 01.02.03
 *
 *		01/21/2009 - DW - Changed an issue in Update Article which caused the first saved category not to be saved.
 * 
 *		02/03/2009 - DW - Forgot to rev the revision number.  Added support for the PublishDate as well as changed the 
 *							code related to redirects after pages are created or edited.  Also applied Lei's fix related
 *							to the way categories are managed in 06.01.
 *  01.02.04
 * 
 *		03/10/2009 - DW - Changes made by Zhen Lei to allow for adding pages from within WLW.
 */


using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Users;
using ZLDNN.Modules.DNNArticle;

namespace ITCrossing
{
	public class metaPostDNNArtilceProvider : IPublishable
	{
		# region IPublishable Members

		# region Public Properties

		/// <summary>
		/// ProviderKey should be set to the Friendly Name of the module for
		/// which this provider is being implemented.
		/// </summary>
		public string ProviderKey
		{
			get
			{
				return MetaPostServices.GetFriendlyNameFromModuleDefinition("DNNArticle");
			}
		}

		/// <summary>
		/// ManifestFilePath is the path including the filename to the manifest file used to determine 
		/// the settings available in Windows Live Writer.  An example path might
		/// be /DesktopModules/itcMetaPost/manifests/wlwblog.xml.  See the following URL for 
		/// information regarding what Content can be placed in a WLW manifest file:
		/// http://msdn2.microsoft.com/en-us/library/bb463260.aspx
		/// </summary>
		public string ManifestFilePath
		{
			get { return "/DesktopModules/DNNArticle/manifests/wlwdnnarticle.xml"; }
		}

		/// <summary>
		/// LocalizationFilePath is the path including the filename to the 
		/// resource file used by the module to retrieve the error messages
		/// shown to the user (eg. "/DesktopModules/custommodule/App_LocalResources/customfilename")
		/// Note that the filename should not include the file extension.
		/// </summary>
		public string LocalizationFilePath
		{
			get { return "/DesktopModules/DNNArticle/App_LocalResources/itcMetaPostDNNArticle"; }
		}

		/// <summary>
		/// OPTIONAL - ImageUploadPath is a property metaPost uses to determine where 
		/// to store the media files (images).  This property should return just a 
		/// section of the path starting from the portal root.  Added to this path will
		/// be the username along with the path 
		/// </summary>
		public string ImageUploadPath
		{
			get
			{
				// This can be overridden with custom implementation if needed.  If
				// overridden, then a message should be placed in the ImagePath column
				// for your provider letting administrators know that administration of
				// the ImagePath is implemented elsewhere.  
				return MetaPostServices.GetProviderImageUploadPath(ProviderKey);
			}
		}

		/// <summary>
		/// AttachmentUploadPath is used to specify the location of attachments added
		/// to a post or page.
		/// </summary>
		public string AttachmentUploadPath
		{
			get
			{
				// For now, we'll just set this to the same as the image upload path
				return MetaPostServices.GetProviderAttachmentUploadPath(ProviderKey);
			}
		}

		/// <summary>
		/// SettingsUserControlPath is for future use.  It will return the path to the
		/// the settings user control for this provider.  
		/// </summary>
		public string SettingsUserControlPath
		{
			get { throw new NotImplementedException(); }
		}

		# endregion

		# region Get Methods

		/// <summary>
		/// The purpose of this procedure is to provide a list of all the modules in a 
		/// given portal to which the currently logged on user has either insert, update
		/// or delete access.  Note, this may not always correspond to an actual module.
		/// For example, with the DNN Blog module provider, a list of blogs is returned
		/// along with URL of where each blog is available within the site.  For the News
		/// Articles module, we return a list of all News Articles modules that have been
		/// added to Tabs throughout the site.
		/// </summary>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		/// <param name="providerKey"></param>
		public ModuleInfoStruct[] GetModulesForUser(UserInfo userInfo, PortalSettings portalSettings, string providerKey)
		{
			//return MetaPostServices.GetModuleInfoStructsByProviderKeyUserIdAndPortalId(
			//    providerKey, userInfo.UserID, portalSettings.PortalId);
			ModuleInfoStruct[] infoArray = null;
			List<ModuleInfoStruct> moduleInfoList = new List<ModuleInfoStruct>();

			List<DnnModuleInfoStruct> dnnModuleInfos = MetaPostServices.GetModuleInfos(providerKey, portalSettings.PortalId);

			if (dnnModuleInfos.Count > 0)
			{
				infoArray = new ModuleInfoStruct[dnnModuleInfos.Count];
				for (int i = 0; i < dnnModuleInfos.Count; i++)
				{

					ModuleInfoStruct moduleInfo = new ModuleInfoStruct();
					ModuleController moduleController = new ModuleController();
					ModuleInfo dnnModuleInfo =
						moduleController.GetModule(dnnModuleInfos[i].ModuleId, dnnModuleInfos[i].TabId, false);
					moduleInfo.ModuleLevelId = dnnModuleInfos[i].TabModuleId.ToString();

					string modulePath = dnnModuleInfos[i].TabPath.Replace("//", "/");
					// remove the beginning forward slash
					if (modulePath.Length > 1 && modulePath.Substring(0, 1) == "/")
						modulePath = modulePath.Substring(1);
					moduleInfo.ModuleName = dnnModuleInfo.ModuleTitle + " (" + modulePath + ")";

					moduleInfo.Url = MetaPostServices.GetRedirectUrl(providerKey, dnnModuleInfos[i].TabId);
					if (dnnModuleInfo.ControlSrc.ToLower() == "DesktopModules/DNNArticle/DNNArticle.ascx".ToLower())
					{
						if (IsUserPrivileged(userInfo, dnnModuleInfo) || IsUserPrivileged(userInfo, MySettings.AddRoles, dnnModuleInfos[i].ModuleId) || IsUserPrivileged(userInfo, MySettings.ApproveRoles, dnnModuleInfos[i].ModuleId))
						{
							moduleInfoList.Add(moduleInfo);
							//break;
						}
					}
				}
				infoArray = moduleInfoList.ToArray();
			}
			else
			{
				throw new MetaPostException("NoModulesForUser",
											"There are no News Article modules associated with this user account.  Please enter a user account which has been associated with a blog.");
			}
			return infoArray;

		}

		/// <summary>
		/// GetRecentItems returns a list of the recent items added to the module.  For example, with
		/// the blog module, the list would return all the recent blog entries.  For the Text/HTML provider, 
		/// this method would return a list of the recently added Text/HTML modules in the site.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="numberOfItems"></param>
		/// <param name="requestType">GetRecentItems can be called for a number of reasons.  In Windows Live Writer,
		/// users are able to retrieve a list of recent posts or recent pages.  The requestType parameter is used
		/// to denote whether a list of pages or posts is being requested.  Additionally, WLW may request a list 
		/// of hiearchical pages to show pages when allowing a parent page to be assigned to a new page.  The values for this enum
		/// are RecentPosts, RecentPages and RecentPagesHiearchical.</param>
		/// <param name="providerKey"></param>
		/// <returns></returns>		
		public Item[] GetRecentItems(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, int numberOfItems, RecentItemsRequestType requestType, string providerKey)
		{
			// Authorize this action
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, moduleLevelId,
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));

			// Get the actual ModuleId since we're tracking the TabModuleId in the moduleLevelId parameter
			int moduleId = MetaPostServices.GetModuleIdByTabModuleId(Convert.ToInt32(moduleLevelId));

			List<Item> itemArray = new List<Item>();
			if (requestType == RecentItemsRequestType.RecentPages)
			{
				DNNArticlePageController ctl = new DNNArticlePageController();
				List<DNNArticlePageInfo> arr = ctl.GetDNNArticlePageByModule(moduleId, userInfo.UserID);
				int count = 0;
				foreach (DNNArticlePageInfo obj in arr)
				{

					count++;
					if (count >= numberOfItems) break;
					Item item = new Item();
					item.ItemId = obj.ItemId.ToString();
					item.Title = HtmlUtils.StripTags(HttpUtility.HtmlDecode(obj.Title), false);
					item.Content = HttpUtility.HtmlDecode(obj.Content);

					itemArray.Add(item);
				}
			}
			else
			{
				int num = numberOfItems;
				if (num == -1) num = 20;
				DNNArticleController ctl = new DNNArticleController();
				// List<DNNArticleInfo> arr = ctl.GetDNNArticles(moduleId, "CreatedDate desc", false);
				List<DNNArticleInfo> arr = ctl.GetTopArticlesBySQL(-1, moduleId.ToString(), "", "UpdateDate desc", num, DisplayType.All, true, -1, false, userInfo.UserID, false, userInfo.UserID, Null.NullDate, Null.NullDate);

				if (arr.Count > 0)
				{
					int count = 0;
					foreach (DNNArticleInfo obj in arr)
					{
						if (obj.CreatedByUser == userInfo.UserID || IsUserPrivileged(userInfo, MySettings.ApproveRoles, Convert.ToInt32(moduleLevelId)))
						{
							Item item = new Item();
							item.ItemId = obj.ItemId.ToString();
							item.Title = HtmlUtils.StripTags(HttpUtility.HtmlDecode(obj.Title), false);
							item.Content = HttpUtility.HtmlDecode(obj.Content);
							item.DateCreated = obj.CreatedDate;
							item.StartDate = obj.PublishDate;
							item.Summary = obj.Description;
							item.SeoFriendlyTitle = obj.SEOTitle;
							item.PageOrder = count.ToString();
							itemArray.Add(item);
							count++;
							if (count >= numberOfItems) break;
						}
					}
				}
				else
				{
					throw new MetaPostException("RecentPostsError",
												"There are no Articles associated with this user account.  Please enter a user account which has been associated with a DNNArticle.");
				}
			}
			return itemArray.ToArray();
		}

		/// <summary>
		/// GetItem is used to retrieve a specific item, which may be a page or a post if your module supports
		/// both concepts.  In cases where a module supports both pages and posts, a concept made available in 
		/// Windows Live Writer, but not in Word 2007 or in many other publishing clients, the itemType parameter 
		/// can be used to distinguish between when this method is being called to add a page or a post.  If your 
		/// provider doesn't support a distinction between pages and posts, then simply ignore the itemType parameter.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="itemType"></param>
		/// <returns></returns>		
		public Item GetItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{
			Item item = new Item();
			if (itemType == ItemType.Post)
			{
				int moduleId = 0;

				moduleId = Convert.ToInt32(GetModuleIdFromItemId(itemId, portalSettings.PortalId));

				DNNArticleController ctl = new DNNArticleController();
				DNNArticleInfo obj = ctl.GetDNNArticle(moduleId, Convert.ToInt32(itemId));

				bool titleContainsHtml = MetaPostServices.ContainsHtml(HttpUtility.HtmlDecode(obj.Title));

				// DW - Removed since the Title should not contain HTML.
				// Feel free to remove if this is correct Lei.
				//if (titleContainsHtml)
				//{
				//    item.Title = MetaPostServices.GetString("TitleContainsHtml", "Titles which contain HTML are managed as a split post.", LocalizationFilePath);
				//    item.Content = obj.Title + obj.Content;
				//}
				//else
				//{
				item.Title = HttpUtility.HtmlDecode(obj.Title);
				item.Content = HttpUtility.HtmlDecode(obj.Content);
				item.Summary = HttpUtility.HtmlDecode(obj.Description);

				//}

				item.Keywords = obj.SEOTags;
				item.SeoFriendlyTitle = obj.SEOTitle;
				item.DateCreated = obj.CreatedDate;
				item.StartDate = obj.PublishDate;
				item.ItemId = obj.ItemId;

				// Use the UserController to look up a user's name
				UserController userController = new UserController();
				UserInfo dnnUserInfo = userController.GetUser(portalSettings.PortalId, Convert.ToInt32(obj.CreatedByUser));

				item.AuthorId = (dnnUserInfo == null) ? string.Empty : dnnUserInfo.DisplayName;

				ArticleAssignedCategoriesController c = new ArticleAssignedCategoriesController();
				List<CategoryInfo> lst = c.GetArticleCategoriesByArticleID(obj.ItemId);

				CategoryController categoryctl = new CategoryController();
				// Get the categories from the controller
				ArrayList Categories = categoryctl.GetByModules(moduleId, false, true);
				int coun = 1;

				foreach (CategoryInfo Cat in Categories)
				{


					Cat.Title = coun.ToString().PadLeft(Categories.Count.ToString().Length) + " " + Cat.Title.Replace(".", " ");
					Cat.Title = Cat.Title.Trim();
					coun++;
					foreach (CategoryInfo a in lst)
					{
						if (a.ItemID == Cat.ItemID)
							a.Title = Cat.Title;
					}
					//if (obj.CategoryID == Cat.ItemID)
					//    obj.CategoryName = Cat.Title;
				}
				item.Categories = new string[lst.Count];
				int count = 0;
				foreach (CategoryInfo a in lst)
				{
					item.Categories.SetValue(a.Title, count);
					count++;
				}
				// item.Categories.SetValue(obj.CategoryName, count);

				FindAndPlaceSummary(ref item);
			}
			//Added by Zhen Lei on 03/10/2009, add page
			else
			{


				item.ItemType = ItemType.Page;
				DNNArticlePageController ctl = new DNNArticlePageController();
				DNNArticlePageInfo obj = ctl.GetDNNArticlePage(Convert.ToInt32(itemId));
				item.Content = HttpUtility.HtmlDecode(obj.Content);
				item.PageOrder = obj.Page.ToString();
				item.ItemId = Convert.ToInt32(itemId);
				item.Title = HttpUtility.HtmlDecode(obj.Title);

				DNNArticleController ctlarticle = new DNNArticleController();
				DNNArticleInfo objarticle = ctlarticle.GetDNNArticleByItemID(obj.ArticleID);
				item.ParentId = objarticle.Title;
			}
			//Added End
			return item;
		}

		# endregion

		# region Add, Edit and Delete Methods

		/// <summary>
		/// NewItem is used for creating new items (either pages or posts).  The implementation 
		/// in your provider can distinguish between page and post requests for NewItem by the 
		/// ItemType property of the Item struct.  Additional properties of the Item Struct which 
		/// may be of interest in the implmentation of this method are: Publish, StyleDetectionPost,StyleId, and ItemType.
		/// See the comments associated with each of these properties of the Item struct for more information.
		/// </summary>
		/// <param name="moduleLevelId">String - ModuleId is a very loose concept here.  Anything can be tracked in this variable as long as it is consistent.  For the Blog module, the BlogId is passed and for the Text/HTML module, the ModuleId is passed and for the Ventrian News Articles module, the ArticleId is passed.  This value is based on the value sent to Windows Live Writer when GetModulesForUser is called. </param>
		/// <param name="userInfo">DotNetNuke UserInfo object.  This UserInfo object is retrieved by metaPost and made available to every method call in the MetaPostProvider interface.</param>
		/// <param name="portalSettings">DotNetNuke PortaSettings object - This is provided to make it easier to work with metaPost.  metaPost does all the work behind the scenes of identifying the right portalSettings object based on the requested URL.</param>
		/// <param name="item">Custom Struct - The item struct contains a list of fields sent through the MetaWeblog API.  The properties have been renamed to make sense in more general applications outside of just blogs.</param>
		/// <returns></returns>
		public string NewItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{

			// Authorize this attempt to create a new item
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, moduleLevelId,
										   GetModulesForUser(userInfo, portalSettings, ProviderKey));

			List<string> images = MetaPostServices.GetImageListFromItem(ref item);

			ExtractSummaryFromExtendedContent(ref item);

			// Get the actual ModuleId since we're tracking the TabModuleId in the moduleLevelId parameter
			int moduleId = MetaPostServices.GetModuleIdByTabModuleId(Convert.ToInt32(moduleLevelId));

			// Tell the Update procedure that we're adding a new item.
			item.ItemId = "-1";

			//Modified by Zhen Lei on 03/10/2009
			int Id;

			if (item.ItemType == ItemType.Post)
			{
				Id = UpdateArticle(item, moduleId, userInfo, portalSettings.Email);
			}
			else
			{
				if (string.IsNullOrEmpty(item.ParentId) || item.ParentId == "0")
				{
					throw new MetaPostException("PageParentRequired", "A page parent is required.  In Windows Live Writer, the Page Parent dropdown appears in the bottom left part of the screen.");
				}
				Id = UpdatePage(item);
			}
			//Modified End

			if (item.ItemType == ItemType.Post)
			{
				ModuleController mc = new ModuleController();
				ModuleInfo mo = mc.GetModule(moduleId, Null.NullInteger, false);
				int tabId = mo.TabID;
				string tempInstallUrl = Globals.NavigateURL(tabId, string.Empty, new string[] { "selectedmoduleid=" + moduleId, "smid=" + moduleId, "ArticleId=" + Id });
				MetaPostServices.SetTempInstallUrl(ProviderKey, tempInstallUrl);
			}

			MetaPostServices.SaveItemImages(Id, images, ProviderKey, portalSettings, userInfo.UserID);

			return Id.ToString();
		}

		/// <summary>
		/// EditItem is called to edit either a page or a post.  The difference
		/// between the two is denoted in a property of the Item struct (ItemType).
		/// An additional property of the Item struct that may be important to the 
		/// implementation of the EditItem method is the Publish property.  This is 
		/// set to true when the item should be published.  The default setting of 
		/// false denotes that the item may be saved as a draft.
		/// 
		/// It's important to note that when Windows Live Writer sends the information 
		///		for a post edit, the moduleLevelId is not passed.  For implementation of 
		///		this procedure in providers which do not support pages, the moduleLevelId 
		///		should be ignored and attempts to get the moduleId can be made by calling
		///		GetModuleIdFromItemId or a similar private procedure.
		/// 
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="item"></param>
		/// <returns></returns>
		public bool EditItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{

			List<string> images = MetaPostServices.GetImageListFromItem(ref item);

			// Get the actual ModuleId 
			string moduleId = GetModuleIdFromItemId((string)item.ItemId, portalSettings.PortalId);

			ExtractSummaryFromExtendedContent(ref item);


			//item.ItemId = item.ItemId;
			//Modified by Zhen Lei on 03/10/2009
			if (item.ItemType == ItemType.Post)
			{
				UpdateArticle(item, Convert.ToInt32(moduleId), userInfo, portalSettings.Email);
			}
			else
			{
				if (string.IsNullOrEmpty(item.ParentId) || item.ParentId == "0")
				{
					throw new MetaPostException("PageParentRequired", "A page parent is required.  In Windows Live Writer, the Page Parent dropdown appears in the bottom left part of the screen.");
				}
				UpdatePage(item);
			}
			//Modified End
			if (item.ItemType == ItemType.Post)
			{
				ModuleController mc = new ModuleController();
				ModuleInfo mo = mc.GetModule(Convert.ToInt32(moduleId), Null.NullInteger, false);
				int tabId = mo.TabID;
				string tempInstallUrl = Globals.NavigateURL(tabId, string.Empty, new string[] { "selectedmoduleid=" + moduleId, "smid=" + moduleId, "ArticleId=" + item.ItemId });
				MetaPostServices.SetTempInstallUrl(ProviderKey, tempInstallUrl);
			}

			MetaPostServices.SaveItemImages(Convert.ToInt32(item.ItemId), images, ProviderKey, portalSettings, userInfo.UserID);

			return true;
		}

		/// <summary>
		/// DeleteItem is used to delete either a page or a post.  The difference between the two is noted 
		/// in the itemType parameter which is an enumeration set to either Page or Post.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="itemType"></param>
		/// <returns></returns>
		public bool DeleteItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{

			# region Code for Cleaning up After Temporary Style Posts
			//
			// Removed to as not to change the data behind the scenes.  
			//
			//// The following code should only be executed if cleaning up after WLW
			//// tries to create a temporary style post.

			//string faqEnableAjax = MetaPostServices.GetTempStyleValue(userInfo.UserID, "FaqEnableAjax");
			//if (!string.IsNullOrEmpty(faqEnableAjax))
			//{
			//    // Retrieve the ModuleId
			//    string faqQuestionTemplate =
			//        MetaPostServices.GetTempStyleValue(userInfo.UserID, "FaqQuestionTemplate");
			//    DataProvider.Instance().UpdateModuleSetting(Convert.ToInt32(moduleId), "FaqEnableAjax", faqEnableAjax);
			//    DataProvider.Instance().UpdateModuleSetting(Convert.ToInt32(moduleId), "FaqQuestionTemplate", faqQuestionTemplate);
			//}
			# endregion

			if (itemType == ItemType.Post)
			{
				DNNArticleController ctl = new DNNArticleController();
				int ModuleID = ctl.GetDNNArticleModuleIDByItemID(int.Parse(itemId));
				ctl.DeleteDNNArticle(ModuleID, Convert.ToInt32(itemId));
			}
			else
			{
				DNNArticlePageController ctl = new DNNArticlePageController();
				ctl.DeleteDNNArticlePage(Convert.ToInt32(itemId));
			}
			return true;
		}

		# endregion

		# region Category Related Procedures

		/// <summary>
		/// GetCategories retrieves a list of categories for a particular module.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>		
		public ItemCategoryInfo[] GetCategories(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings)
		{
			// Get the actual ModuleId since we're tracking the TabModuleId in the moduleLevelId parameter
			int moduleId = MetaPostServices.GetModuleIdByTabModuleId(Convert.ToInt32(moduleLevelId));

			List<ItemCategoryInfo> catInfoList = new List<ItemCategoryInfo>();

			CategoryController categoryctl = new CategoryController();


			// Get the categories from the controller
			ArrayList Categories = categoryctl.GetByModules(moduleId, false, true);
			int c = 1;
			foreach (CategoryInfo Cat in Categories)
			{
				ItemCategoryInfo catInfo = new ItemCategoryInfo();
				catInfo.CategoryId = Cat.ItemID;

				string s = c.ToString().PadLeft(Categories.Count.ToString().Length);

				catInfo.CategoryName = s + " " + Cat.Title.Replace(".", " ");  //Cat.ItemID.ToString();
				catInfo.Description = s + " " + Cat.Title.Replace(".", " "); //s + c.ToString() + " " + Cat.Title;
				c++;
				catInfo.HtmlUrl = "";
				catInfo.RssUrl = "";
				catInfo.ParentId = 0;

				catInfoList.Add(catInfo);
			}
			return catInfoList.ToArray();
		}

		public bool SetItemCategories(string itemId, ItemCategory[] itemCategories, UserInfo userInfo,
								PortalSettings portalSettings)
		{
			// Not yet implemented.
			return true;
		}

		public ItemCategory[] GetItemCategories(string itemId, UserInfo userInfo,
												PortalSettings portalSettings)
		{
			int moduleId = 0;
			List<ItemCategory> itemCategories = new List<ItemCategory>();
			DNNArticleController ctl = new DNNArticleController();
			DNNArticleInfo obj = ctl.GetDNNArticle(moduleId, Convert.ToInt32(itemId));
			ArticleAssignedCategoriesController c = new ArticleAssignedCategoriesController();
			List<CategoryInfo> lst = c.GetArticleCategoriesByArticleID(obj.ItemId);


			moduleId = Convert.ToInt32(GetModuleIdFromItemId(itemId, portalSettings.PortalId));

			CategoryController categoryctl = new CategoryController();
			// Get the categories from the controller
			ArrayList Categories = categoryctl.GetByModules(moduleId, false, true);
			int coun = 1;
			foreach (CategoryInfo Cat in Categories)
			{

				Cat.Title = coun.ToString().PadLeft(Categories.Count.ToString().Length) + " " + Cat.Title.Replace(".", " ");

				coun++;
				foreach (CategoryInfo a in lst)
				{
					if (a.ItemID == Cat.ItemID)
						a.Title = Cat.Title;
				}
			}

			int count = 0;
			foreach (CategoryInfo a in lst)
			{
				ItemCategory ic = new ItemCategory();
				ic.CategoryId = a.ItemID.ToString();
				ic.CategoryName = a.Title;
				if (obj.CategoryID == a.ItemID)
				{
					// This is the default category so we'll set the IsPrimary
					// to true
					ic.IsPrimary = true;
				}
				else
				{
					ic.IsPrimary = false;
				}
				itemCategories.Add(ic);
			}
			return itemCategories.ToArray();
		}

		/// <summary>
		/// Used to add a new category for modules which support this feature.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		public int NewCategory(string moduleLevelId, NewItemCategory category, UserInfo userInfo, PortalSettings portalSettings)
		{
			int categoryId = 0;
			// Check first to see if the user should have the ability to add Categories

			ModuleController moduleController = new ModuleController();
			//ModuleInfo moduleInfo =
			//    moduleController.getm(portalSettings.PortalId, moduleName);
			//bool bHasAdminRights = PortalSecurity.IsInRoles(_moduleConfiguration.AuthorizedEditRoles);
			//Dim blnHasModuleEditPermissions As Boolean = PortalSecurity.IsInRoles(_moduleConfiguration.AuthorizedEditRoles)
			throw new MetaPostException("FeatureNotImplemented",
										"This feature is currently not implemented.");

			return categoryId;
		}

		# endregion

		#endregion

		# region Private Procedures Specific to DNNArticle

		/// <summary>
		/// GetModuleIdFromItemId is not needed for most modules.  It called form the underlying EditPost 
		/// procedure since WLW only passes the ItemId to this procedure and not the ModuleId.  Currently,
		/// the only reason this implementation is needed is due to a call to GetSummaryMaxLength which 
		/// requires the moduleLevelId.  While GetModuleIdFromItemId isn't needed for external access to the provider
		/// it is needed for the FAQs provider for the GetItem method which calls it.
		/// </summary>
		/// <param name="itemId"></param>
		/// <returns></returns>
		/// <param name="portalId"></param>
		private string GetModuleIdFromItemId(string itemId, int portalId)
		{
			int moduleId;
			DNNArticleController ctl = new DNNArticleController();
			moduleId = ctl.GetDNNArticleModuleIDByItemID(int.Parse(itemId));
			return moduleId.ToString();
		}

		private int UpdateArticle(Item item, int moduleId, UserInfo userInfo, string email)
		{
			DNNArticleController ctl = new DNNArticleController();

			int Id = 0;

			# region "removed by Zhen Lei on 03/12/2009"
			//	CategoryInfo selectedCatInfo = null;


			// Check to see if we have a category selected
			//if (item.Categories.Length > 0)
			//{
			//    string selectedCategory = item.Categories[0].Substring(item.Categories[0].IndexOf(" ") + 1, item.Categories[0].Length - item.Categories[0].IndexOf(" ") - 1);

			//    foreach (CategoryInfo cat in categories)
			//    {
			//        if (cat.Title.Replace(".", " ") == selectedCategory)
			//        {
			//            selectedCatInfo = cat;
			//            break;
			//        }
			//    }

			//}
			//else
			//{
			//    if (categories.Count > 0)
			//        selectedCatInfo = (CategoryInfo)categories[0];
			//}
			#endregion

			DNNArticleInfo obj;
			if (Convert.ToInt32(item.ItemId) == -1)
				obj = new DNNArticleInfo();
			else
				obj = ctl.GetDNNArticle(moduleId, Convert.ToInt32(item.ItemId));


			obj.ItemId = (item.ItemId.ToString() == "-1") ? -1 : Convert.ToInt32(item.ItemId);
			//if (selectedCatInfo != null) obj.CategoryID = selectedCatInfo.ItemID;
			obj.CategoryID = -1;
			obj.Title = item.Title;
			obj.Content = item.Content;
			obj.Description = item.Summary;
			obj.SEOTitle = item.SeoFriendlyTitle;
			obj.SEOTags = item.Keywords;
			obj.Tags = item.Keywords;

			obj.UpdateDate = DateTime.Now;

			obj.Clicks = 0;
			obj.IsApproved = IsApprove(userInfo, moduleId);

			//PropertyInfo pi = obj.GetType().GetProperty("PublishDate");
			//if (pi != null)
			//{
			//    // We should try to set the PublishDate to the date of the item.
			//    pi.SetValue(obj, item.StartDate, null);
			//}

			obj.ModuleId = Convert.ToInt32(moduleId);

			if (obj.ItemId == -1)
			{
				obj.CreatedByUser = userInfo.UserID;
				obj.CreatedDate = DateTime.Now;
				if (!Null.IsNull(item.StartDate))
					obj.PublishDate = item.StartDate;
				else
					obj.PublishDate = obj.CreatedDate;
				Id = ctl.AddDNNArticle(obj);
			}
			else
			{
				ctl.UpdateDNNArticle(obj);
				Id = obj.ItemId;
				if (!Null.IsNull(item.StartDate))
					obj.PublishDate = item.StartDate;
			}
			SendEmail(obj, moduleId, email);

			//Save categories by Zhen Lei on 03/12/2009
			CategoryController categoryctl = new CategoryController();

			ArrayList categories = categoryctl.GetByModules(moduleId, false, true);

			ArticleAssignedCategoriesController c = new ArticleAssignedCategoriesController();

			if (item.Categories.Length > 0)
			{

				foreach (CategoryInfo ca in categories)
				{
					c.Delete(ca.ItemID, Id);
					//ca.IsAutoApprove = false;
				}
				foreach (string cat in item.Categories)
				{
					string s = cat.Trim();
					s = s.Substring(s.IndexOf(" ") + 1, s.Length - s.IndexOf(" ") - 1).Trim();
					foreach (CategoryInfo ca in categories)
					{

						if (ca.Title.Replace(".", " ").Trim() == s)
						{
							ArticleAssignedCategoriesInfo o = new ArticleAssignedCategoriesInfo();
							o.ArticleID = Id;
							o.CategoryID = ca.ItemID;
							c.AddDNNArticleCategories(o);
							// ca.IsAutoApprove = true;
							break;
						}
					}
				}
				//foreach (CategoryInfo ca in categories)
				//{
				//    ArticleAssignedCategoriesInfo o = c.GetArticleAssignedCategories(ca.ItemID, Id);
				//    if (ca.IsAutoApprove)
				//    {
				//        if (o == null)
				//        {
				//            o = new ArticleAssignedCategoriesInfo();
				//            o.ArticleID = Id;
				//            o.CategoryID = ca.ItemID;
				//            c.AddDNNArticleCategories(o);
				//        }
				//    }
				//    else
				//    {
				//        if (o != null)
				//        {
				//            c.Delete(o.CategoryID, o.ArticleID);
				//        }
				//    }
				//}
			}
			else
			{
				//if no selected categories, add the first category
				if (categories.Count > 0)
				{
					ArticleAssignedCategoriesInfo o = new ArticleAssignedCategoriesInfo();
					o.ArticleID = Id;
					o.CategoryID = ((CategoryInfo)categories[0]).ItemID;
					c.AddDNNArticleCategories(o);
				}

			}

			return Id;
		}

		//Added by Zhen Lei on 03/10/2009
		private int UpdatePage(Item item)
		{
			DNNArticlePageController ctl = new DNNArticlePageController();
			DNNArticlePageInfo obj = ctl.GetDNNArticlePage(Convert.ToInt32(item.ItemId));
			if (obj == null)
			{
				obj = new DNNArticlePageInfo();
				obj.ItemId = -1;
			}
			if (obj.ItemId == -1) obj.ArticleID = Convert.ToInt32(item.ParentId);
			if (string.IsNullOrEmpty(item.PageOrder) || item.PageOrder == "0")
			{
				if (obj.ItemId == -1)
					obj.Page = ctl.GetLastPageNumber(obj.ArticleID) + 1;
			}
			else
			{
				obj.Page = Convert.ToInt32(item.PageOrder);
			}

			obj.Title = item.Title;

			if (item.Content == "")
				obj.Content = item.Summary;
			else
				obj.Content = item.Content;

			if (obj.ItemId == -1)
			{
				obj.ItemId = ctl.AddDNNArticlePage(obj);

			}
			else
			{
				ctl.UpdateDNNArticlePage(obj);
			}
			return obj.ItemId;

		}
		//Added End

		private void SendEmail(DNNArticleInfo obj, int moduleId, string email)
		{
			if (IsEmail(moduleId))
			{
				DNNArticleController c = new DNNArticleController();
				string body = obj.CategoryName + ":" + obj.Title;

				DotNetNuke.Services.Mail.Mail.SendMail(email, EmailTo(moduleId, email), "", "", DotNetNuke.Services.Mail.MailPriority.Normal, EmailSubject(moduleId), DotNetNuke.Services.Mail.MailFormat.Html, System.Text.Encoding.UTF8, body, "", "", "", "", "");

			}
		}

		private bool IsApprove(UserInfo userInfo, int moduleId)
		{
			bool retValue = false;

			Hashtable moduleSettings = PortalSettings.GetModuleSettings(moduleId);

			if (moduleSettings.Contains(MySettings.AutoApprove))
			{
				retValue = Convert.ToBoolean(moduleSettings.Contains(MySettings.AutoApprove));
			}

			retValue = retValue || IsUserPrivileged(userInfo, MySettings.ApproveRoles, moduleId);
			return retValue;
		}

		private bool IsUserPrivileged(UserInfo userInfo, ModuleInfo dnnModuleInfo)
		{
			bool retValue = false;
			string roles = dnnModuleInfo.AuthorizedEditRoles;
			string[] rolesArray = roles.Split(';');
			foreach (string role in rolesArray)
			{
				if (userInfo.IsSuperUser || userInfo.IsInRole(role))
				{
					retValue = true;
					return retValue;
				}
			}
			return retValue;
		}

		private bool IsUserPrivileged(UserInfo userInfo, string roleGroup, int moduleLevelId)
		{
			bool retValue = false;

			Hashtable moduleSettings = PortalSettings.GetModuleSettings(moduleLevelId);
			if (moduleSettings.Contains(roleGroup))
			{
				string roles = moduleSettings[roleGroup].ToString();
				string[] rolesArray = roles.Split(';');
				foreach (string role in rolesArray)
				{
					if (userInfo.IsSuperUser || userInfo.IsInRole(role))
					{
						retValue = true;
						return retValue;
					}
				}
			}
			else
			{
				if (userInfo.IsSuperUser)
				{
					retValue = true;
					return retValue;
				}
			}

			return retValue;
		}

		private string GetSettingValue(int moduleid, string key)
		{
			Hashtable moduleSettings = PortalSettings.GetModuleSettings(moduleid);
			if (moduleSettings.Contains(key))
			{
				return moduleSettings[key].ToString();

			}
			else
				return null;
		}

		private bool IsEmail(int moduleid)
		{
			string k = GetSettingValue(moduleid, MySettings.IsSendEmail);
			if (k != null)
				return bool.Parse(k);
			else
				return false;
		}

		private string EmailSubject(int moduleid)
		{
			string k = GetSettingValue(moduleid, MySettings.EmailSubject);
			if (k != null)
				return k;
			else
				return "New Article";
		}

		private string EmailTo(int moduleid, string def)
		{
			string k = GetSettingValue(moduleid, MySettings.Email);
			if (k != null)
				return k;
			else
				return def;
		}

		private void ExtractSummaryFromExtendedContent(ref Item item)
		{
			if (!string.IsNullOrEmpty(item.ExtendedContent))
			{
				// Extract the summary from the excerpt
				item.Summary = item.Content;
				item.Content = item.ExtendedContent;
			}
			// Also check to see if there is only one part to the content (no summary and 
			// no extended content).  In this case, we'll just submit a summary.
			if (string.IsNullOrEmpty(item.Summary) && string.IsNullOrEmpty(item.ExtendedContent))
			{
				item.Summary = item.Content;
				item.Content = "";
			}
		}

		private void FindAndPlaceSummary(ref Item item)
		{
			// DW - 06/24/2008 - mt_Excerpt isn't supported in this provider, so we need to show
			// all the content through the Content property.
			//if (!string.IsNullOrEmpty(item.Summary)
			//    && !string.IsNullOrEmpty(item.Content)) //MetaPostServices.ContainsHtml(item.Summary)
			//{
			item.Content = item.Summary + "<!--more-->" + item.Content;
			item.Summary = "";
			//}
		}


		# endregion

	}
}
